-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local lu = require 'luaunit'
local c_topo_monitor = require 'biz_topo.topo_monitor'
local c_business_connector = require 'biz_topo.class.business_connector'
local c_unit_configuration = require 'biz_topo.class.unit_configuration'
local signal = require 'mc.signal'
local bs = require 'mc.bitstring'
local skynet = require 'skynet'
local c_topo_reader = require 'biz_topo.topo_reader'
local ctx = require 'mc.context'
local sd_bus = require 'sd_bus'
TestTopoMonitorNew = {}
TestTopoMonitorNew.mock_complete_signal = signal.new()

local mock_complete_signal = signal.new()
local bus = false

local bs_topo = bs.new([[<<
    target_port_id:8,
    index:8,
    uid:24/string,
    port_id:8,
    _:1/string,
    bcu_index:8,
    _:3/string
>>]])

local function to_hex(data)
    return data:gsub('.', function(v)
        return string.format('%d', v:byte())
    end)
end
 
local function create_biz_topo_node(test_data, slot)
    local data = ''
    for _, d in pairs(test_data) do
        data = data .. bs_topo:pack(d)
    end
    return {
        mds_obj = {
            Slot = slot,
            RefSmcChip = {
                Read = function(...)
                    return data
                end
            },
            Type = "Proxy"
        }
    }
end

local function create_biz_conn_objs(test_data)
    local result = {}
    for i, d in pairs(test_data) do
        result[#result + 1] = c_business_connector.new({
            ['bmc.kepler.Systems.UnitConfigError'] = {Port1LinkInfo = '', Port1Status = 0,
            Port2Status = 0, Port2LinkInfo = ''},
            Ports = {d},
            BCUIndex = d.BCUIndex
        }, 1, mock_complete_signal)
    end
    return result
end

local function create_unit_conf_objs(test_data)
    local result = {}
    for _, d in pairs(test_data) do
        result[#result + 1] = c_unit_configuration.new({
            ['bmc.kepler.Systems.UnitConfigError'] = {
                Port1LinkInfo = '', Port2LinkInfo = '',
                Port1Status = 0, Port2Status = 0},
            SlotType = d.slot_type,
            SlotNumber = d.slot_number,
            SlotSilkText = d.silk_text,
            Configurations = d.configs
        }, 1)
    end
    return result
end

-- TOPO检测SMC命令响应体
local bs_topo_resp = bs.new([[<<
    target_port_id:8,
    index:8,
    uid:24/string,
    port_id:8,
    _:1/string,
    bcu_index:8,
    _:3/string
>>]])

local ZONE_A <const> = 'A'
local ZONE_B <const> = 'B'
local ZONE_C <const> = 'C'
local ZONE_D <const> = 'D'
local ZONE_E <const> = 'E'
local ZONE_F <const> = 'F'

-- TOPO检测SMC命令字
local TOPO_CMD_OFFSET <const> = {
    [ZONE_A] = 0xc005100,
    [ZONE_B] = 0xc005500,
    [ZONE_C] = 0xc005900,
    [ZONE_D] = 0xc005d00,
    [ZONE_E] = 0xc006100,
    [ZONE_F] = 0xc006500
}

local TOPO_RESP_LEN <const> = 32           -- 单条响应数据大小为32Byte
local RESP_NUM_PER_ZONE <const> = 32       -- 完整的响应数量为32
local TOPO_RESP_LEN_PER_ZONE <const> = 1024 -- 完整的为32*32 Byte
local RETRY_TIMES <const> = 3              -- SMC数据读取异常重试次数

local function topo_read(chip, offset, len)
    if not chip then
        return false
    end
    local ok, ret1, ret2
    for _ = 1, RETRY_TIMES do
        ok, ret1 = pcall(function()
            return chip:Read(ctx.new(), offset, len)
        end)
        if not ok then
            goto next
        end
        ok, ret2 = pcall(function()
            return chip:Read(ctx.new(), offset, len)
        end)
        if not ok then
            goto next
        end
        -- 比较两次读取结果，若不同则重新读取
        if ret1 == ret2 then
            break
        else
            ok = false
        end
        ::next::
    end

    return ok, ret1
end

local function is_resp_valid(resp)
    return resp.target_port_id ~= 0 and resp.target_port_id ~= 0xff
end

local function plugin_read_topo_info(chip, zone_support)
    local topo_info = {}
    local ok, data, resp_bin, resp
    if not zone_support then
        return false, {}
    end

    for zone, offset in pairs(TOPO_CMD_OFFSET) do
        if not zone_support[zone] then
            goto next
        end
        topo_info[zone] = {}
        ok, data = topo_read(chip, offset, TOPO_RESP_LEN_PER_ZONE)
        if not ok then
            return false, {}
        end
        for i = 1, RESP_NUM_PER_ZONE do
            if #data < i * TOPO_RESP_LEN then
                break
            end
            resp_bin = string.sub(data, (i - 1) * TOPO_RESP_LEN + 1, i * TOPO_RESP_LEN)
            resp = bs_topo_resp:unpack(resp_bin)
            -- target_port_id为0判断为无效信息
            if is_resp_valid(resp) then
                topo_info[zone][resp.port_id] = topo_info[zone][resp.port_id] and topo_info[zone][resp.port_id] or {}
                topo_info[zone][resp.port_id][resp.bcu_index] = resp
            end
        end
        ::next::
    end
    
    return ok, topo_info
end

local function run_topo_monitor(topo_monitor, conn_objs, unit_confs)
    -- read_topo_info
    local zone_support = topo_monitor.topo_reader:init_support_zone()
    topo_monitor.topo_reader.read_topo_info = function(...)
        return plugin_read_topo_info(topo_monitor.topo_reader.biz_topo_node.mds_obj.RefSmcChip, zone_support)
    end
    -- 解析bcu smc命令数据
    local _, topo_info = topo_monitor.topo_reader:read_topo_info()
    for _, config in pairs(unit_confs) do
        topo_monitor.init_config_match_info(config)
    end
    -- 先检测bcu biz connector
    for _, conn in pairs(conn_objs) do
        topo_monitor.init_biz_connector_match_info(conn)
        topo_monitor.set_topo_info_to_biz_connector(conn, topo_info, topo_monitor)
        topo_monitor.match_topo_info_with_config(conn, topo_monitor)
        -- 因为有防抖需要设置2次
        topo_monitor.update_port_status(conn, topo_monitor)
        topo_monitor.update_port_status(conn, topo_monitor)
    end

    -- 再检测unit configuration
    for _, config in pairs(unit_confs) do
        -- 因为有防抖需要设置2次
        topo_monitor.update_config_status(config, topo_monitor)
        topo_monitor.update_config_status(config, topo_monitor)
    end
end

local test_seu_with_two_configs_data<const> = {
    BCU_SLOT = 0,
    biz_topo_node = {
        {target_port_id = 49, index = 0, uid = '00000001030302064317', port_id = 25, bcu_index = 1}, -- D7a
        {target_port_id = 65, index = 0, uid = '00000001030302064317', port_id = 13, bcu_index = 2}, -- cC4a
        {target_port_id = 81, index = 0, uid = '00000001030302064317', port_id = 25, bcu_index = 2},  -- D7a
        {target_port_id = 97, index = 0, uid = '00000001030302064317', port_id = 21, bcu_index = 2} -- D6a
    },
    biz_conn_data = {
        {Name = 'D7a', ID = 25, Offset = 0, Width = 8, BCUIndex = 1}, 
        {Name = 'C4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'D7a', ID = 25, Offset = 0, Width = 8, BCUIndex = 2}, 
        {Name = 'D6a', ID = 21, Offset = 0, Width = 8, BCUIndex = 2}
    },
    unit_conf_data = {
        {
            slot_type = 'SEU',
            slot_number = 1,
            silk_text = 'SEUSlot1',
            configs = {
                {
                    UID = '00000001030302064317',
                    Index = 0,
                    BCUIndex = 1,
                    SrcPortName = {'D7a'},
                    TargetPortID = {49},
                    Slot = {0,1},
                    Device = {}
                },
                {
                    UID = '00000001030302064317',
                    Index = 0,
                     BCUIndex = 2,
                    SrcPortName = {'C4a', 'D7a', 'D6a'},
                    TargetPortID = {65,81,97},
                    Slot = {2,3,4,5,6,7},
                    Device = {}
                }
            }
        } 
    },
    uid_list = {['00000001030302064317'] = true},
    uid_slot_list = {
        IEU = {},
        SEU = {[1] = '00000001030302064317'}
    }
}

function TestTopoMonitorNew:test_seu_with_two_configs()
    -- 模拟bcu smc命令
    local biz_topo_node = create_biz_topo_node(test_seu_with_two_configs_data.biz_topo_node,
       test_seu_with_two_configs_data.BCU_SLOT)
    -- 模拟bcu的biz connector
    local conn_objs = create_biz_conn_objs(test_seu_with_two_configs_data.biz_conn_data)
    -- 模拟psr的unit configuration
    local unit_confs = create_unit_conf_objs(test_seu_with_two_configs_data.unit_conf_data)

    -- 创建线缆检测对象
    local topo_monitor = c_topo_monitor.new(bus, biz_topo_node, conn_objs, unit_confs)
    -- 输入当前自发现发现的uid列表
    topo_monitor.uid_list = test_seu_with_two_configs_data.uid_list
    topo_monitor.uid_slot_list = test_seu_with_two_configs_data.uid_slot_list

    -- 运行线缆检测逻辑
    run_topo_monitor(topo_monitor, conn_objs, unit_confs)

    -- 检查数据
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001030302064317(SEUSlot1)')
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 1)

    conn_objs[#conn_objs + 1] = c_business_connector.new({
            ['bmc.kepler.Systems.UnitConfigError'] = {Port1LinkInfo = '', Port1Status = 0,
            Port2Status = 0, Port2LinkInfo = ''},
            Ports = { 
                {Name = 'D7a', ID = 25, Offset = 0, Width = 8, BCUIndex = 1}, 
                {Name = 'D7a', ID = 25, Offset = 0, Width = 8, BCUIndex = 1}
            },
            BCUIndex = 1
        }, 1, mock_complete_signal)
    run_topo_monitor(topo_monitor, conn_objs, unit_confs)
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 1)        
end

-- BCU1的配置匹配成功，BCU2配置未匹配
local test_ieu_with_two_configs_data<const> = {
    BCU_SLOT = 0,
    biz_topo_node = {
        {target_port_id = 49, index = 0, uid = '00000001040302064316', port_id = 13, bcu_index = 1}, -- C4a
        {target_port_id = 17, index = 0, uid = '00000001040302064316', port_id = 5, bcu_index = 2}, -- B2a
        {target_port_id = 49, index = 0, uid = '00000001040302064316', port_id = 17, bcu_index = 2}, -- C5a
        {target_port_id = 17, index = 0, uid = '00000001040302064316', port_id = 1, bcu_index = 2}, -- B1a
        {target_port_id = 49, index = 0, uid = '00000001040302064316', port_id = 13, bcu_index = 2} -- A4a
    },
    biz_conn_data = {
        {Name = 'C4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 1},
        {Name = 'B1a', ID = 1, Offset = 1, Width = 8, BCUIndex = 2},
        {Name = 'C5a', ID = 17, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'B2a', ID = 5, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'A4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 2}
    },
    unit_conf_data = {
        {
            slot_type = 'IEU',
            slot_number = 1,
            silk_text = 'IEUSlot1',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 1,
                    SrcPortName = {'C4a'},
                    TargetPortID = {49},
                    Slot = {5,255},
                    Device = {}
                }
            }
        }, {
            slot_type = 'IEU',
            slot_number = 2,
            silk_text = 'IEUSlot2',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 2,
                    SrcPortName = {'B2a', 'C5a'},
                    TargetPortID = {17, 49},
                    Slot = {3, 4},
                    Device = {}
                }
            }
        }, 
        {
            slot_type = 'IEU',
            slot_number = 3,
            silk_text = 'IEUSlot3',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 2,
                    SrcPortName = {'B1a', 'A4a'},
                    TargetPortID = {17, 49},
                    Slot = {1, 2},
                    Device = {}
                }
            }
        }
    },
    uid_list = {['00000001040302064316'] = true},
    uid_slot_list = {
        IEU = {[1] = '00000001040302064316', [2] = '00000001040302064316', [3] = '00000001040302064316'},
        SEU = {}
    }
}

function TestTopoMonitorNew:test_ieu_with_two_bcu1()
    -- 模拟bcu smc命令
    local biz_topo_node = create_biz_topo_node(test_ieu_with_two_configs_data.biz_topo_node,
        test_ieu_with_two_configs_data.BCU_SLOT)
    -- 模拟bcu的biz connector
    local conn_objs = create_biz_conn_objs(test_ieu_with_two_configs_data.biz_conn_data)
    -- 模拟psr的unit configuration
    local unit_confs = create_unit_conf_objs(test_ieu_with_two_configs_data.unit_conf_data)

    -- 创建线缆检测对象
    local topo_monitor = c_topo_monitor.new(bus, biz_topo_node, conn_objs, unit_confs)
    -- 输入当前自发现发现的uid列表
    topo_monitor.uid_list = test_ieu_with_two_configs_data.uid_list
    topo_monitor.uid_slot_list = test_ieu_with_two_configs_data.uid_slot_list

    -- 运行线缆检测逻辑
    run_topo_monitor(topo_monitor, conn_objs, unit_confs)

    -- 检查数据
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot1)')
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 1)
    lu.assertEquals(unit_confs[2].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot2)')
    lu.assertEquals(unit_confs[2].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 1)
      lu.assertEquals(unit_confs[3].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot3)')
    lu.assertEquals(unit_confs[3].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 1)
end

local test_ieu_with_two_configs_data_absent<const> = {
    BCU_SLOT = 0,
    --B2a 与 B1a 插错
    biz_topo_node = {
        {target_port_id = 49, index = 0, uid = '00000001040302064316', port_id = 13, bcu_index = 1}, -- C4a
        {target_port_id = 33, index = 0, uid = '00000001040302064316', port_id = 5, bcu_index = 2}, -- B2a
        {target_port_id = 49, index = 1, uid = '00000001040302064316', port_id = 17, bcu_index = 2}, -- C5a
        {target_port_id = 33, index = 1, uid = '00000001040302064316', port_id = 1, bcu_index = 2}, -- B1a
        {target_port_id = 49, index = 2, uid = '00000001040302064316', port_id = 13, bcu_index = 2} -- A4a
    },
    biz_conn_data = {
        {Name = 'C4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 1},
        {Name = 'B1a', ID = 1, Offset = 1, Width = 8, BCUIndex = 2},
        {Name = 'C5a', ID = 17, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'B2a', ID = 5, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'A4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 2}
    },
    unit_conf_data = {
        {
            slot_type = 'IEU',
            slot_number = 1,
            silk_text = 'IEUSlot1',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 1,
                    SrcPortName = {'C4a'},
                    TargetPortID = {49},
                    Slot = {5,255},
                    Device = {}
                }
            }
        }, {
            slot_type = 'IEU',
            slot_number = 2,
            silk_text = 'IEUSlot2',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 2,
                    SrcPortName = {'B2a', 'C5a'},
                    TargetPortID = {17, 49},
                    Slot = {3, 4},
                    Device = {}
                }
            }
        }, 
        {
            slot_type = 'IEU',
            slot_number = 3,
            silk_text = 'IEUSlot3',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 2,
                    SrcPortName = {'B1a', 'A4a'},
                    TargetPortID = {17, 49},
                    Slot = {1, 2},
                    Device = {}
                }
            }
        }
    },
    uid_list = {['00000001040302064316'] = true},
    uid_slot_list = {
        IEU = {[1] = '00000001040302064316', [2] = '00000001040302064316', [3] = '00000001040302064316'},
        SEU = {}
    }
}

-- BCU2的配置部分匹配，报线缆少插告警
function TestTopoMonitorNew:test_ieu_with_two_bcu2()
    -- 模拟bcu smc命令
    local biz_topo_node = create_biz_topo_node(test_ieu_with_two_configs_data_absent.biz_topo_node,
        test_ieu_with_two_configs_data_absent.BCU_SLOT)
    -- 模拟bcu的biz connector
    local conn_objs = create_biz_conn_objs(test_ieu_with_two_configs_data_absent.biz_conn_data)
    -- 模拟psr的unit configuration
    local unit_confs = create_unit_conf_objs(test_ieu_with_two_configs_data_absent.unit_conf_data)

    -- 创建线缆检测对象
    local topo_monitor = c_topo_monitor.new(bus, biz_topo_node, conn_objs, unit_confs)
    -- 输入当前自发现发现的uid列表
    topo_monitor.uid_list = test_ieu_with_two_configs_data_absent.uid_list
    topo_monitor.uid_slot_list = test_ieu_with_two_configs_data_absent.uid_slot_list

    -- 运行线缆检测逻辑
    run_topo_monitor(topo_monitor, conn_objs, unit_confs)

    -- 检查数据
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 1)
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot1)')
    
    lu.assertEquals(unit_confs[2].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 5)
    lu.assertEquals(unit_confs[2].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot2)')

    lu.assertEquals(unit_confs[3].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 5)
    lu.assertEquals(unit_confs[3].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot3)')        
end

local test_ieu_with_two_configs_data_absent2<const> = {
    BCU_SLOT = 0,
    --B2a 与 B1a 插错
    biz_topo_node = {
        {target_port_id = 49, index = 0, uid = '00000001040302064316', port_id = 13, bcu_index = 1}, -- C4a
        {target_port_id = 49, index = 1, uid = '00000001040302064316', port_id = 17, bcu_index = 2}, -- C5a
        {target_port_id = 49, index = 2, uid = '00000001040302064316', port_id = 13, bcu_index = 2} -- A4a
    },
    biz_conn_data = {
        {Name = 'C4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 1},
        {Name = 'B1a', ID = 1, Offset = 1, Width = 8, BCUIndex = 2},
        {Name = 'C5a', ID = 17, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'B2a', ID = 5, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'A4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 2}
    },
    unit_conf_data = {
        {
            slot_type = 'IEU',
            slot_number = 1,
            silk_text = 'IEUSlot1',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 1,
                    SrcPortName = {'C4a'},
                    TargetPortID = {49},
                    Slot = {5,255},
                    Device = {}
                }
            }
        }, {
            slot_type = 'IEU',
            slot_number = 2,
            silk_text = 'IEUSlot2',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 2,
                    SrcPortName = {'B2a', 'C5a'},
                    TargetPortID = {17, 49},
                    Slot = {3, 4},
                    Device = {}
                }
            }
        }, 
        {
            slot_type = 'IEU',
            slot_number = 3,
            silk_text = 'IEUSlot3',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 2,
                    SrcPortName = {'B1a', 'A4a'},
                    TargetPortID = {17, 49},
                    Slot = {1, 2},
                    Device = {}
                }
            }
        }
    },
    uid_list = {['00000001040302064316'] = true},
    uid_slot_list = {
        IEU = {[1] = '00000001040302064316', [2] = '00000001040302064316', [3] = '00000001040302064316'},
        SEU = {}
    }
}

-- BCU2的配置部分匹配，报线缆少插告警
function TestTopoMonitorNew:test_ieu_with_two_bcu3()
    -- 模拟bcu smc命令
    local biz_topo_node = create_biz_topo_node(test_ieu_with_two_configs_data_absent2.biz_topo_node,
        test_ieu_with_two_configs_data_absent2.BCU_SLOT)
    -- 模拟bcu的biz connector
    local conn_objs = create_biz_conn_objs(test_ieu_with_two_configs_data_absent2.biz_conn_data)
    -- 模拟psr的unit configuration
    local unit_confs = create_unit_conf_objs(test_ieu_with_two_configs_data_absent2.unit_conf_data)

    -- 创建线缆检测对象
    local topo_monitor = c_topo_monitor.new(bus, biz_topo_node, conn_objs, unit_confs)
    -- 输入当前自发现发现的uid列表
    topo_monitor.uid_list = test_ieu_with_two_configs_data_absent.uid_list
    topo_monitor.uid_slot_list = test_ieu_with_two_configs_data_absent.uid_slot_list

    -- 运行线缆检测逻辑
    run_topo_monitor(topo_monitor, conn_objs, unit_confs)

    -- 检查数据
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 1)
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot1)')
    
    lu.assertEquals(unit_confs[2].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 5)
    lu.assertEquals(unit_confs[2].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot2)')

    lu.assertEquals(unit_confs[3].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 5)
    lu.assertEquals(unit_confs[3].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot3)')        
end


local test_ieu_with_two_configs_data_absent3<const> = {
    BCU_SLOT = 0,
    --B2a 与 B1a 插错
    biz_topo_node = {
    },
    biz_conn_data = {
        {Name = 'C4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 1},
        {Name = 'B1a', ID = 1, Offset = 1, Width = 8, BCUIndex = 2},
        {Name = 'C5a', ID = 17, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'B2a', ID = 5, Offset = 0, Width = 8, BCUIndex = 2},
        {Name = 'A4a', ID = 13, Offset = 0, Width = 8, BCUIndex = 2}
    },
    unit_conf_data = {
        {
            slot_type = 'IEU',
            slot_number = 1,
            silk_text = 'IEUSlot1',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 1,
                    SrcPortName = {'C4a'},
                    TargetPortID = {49},
                    Slot = {5,255},
                    Device = {}
                }
            }
        }, {
            slot_type = 'IEU',
            slot_number = 2,
            silk_text = 'IEUSlot2',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 2,
                    SrcPortName = {'B2a', 'C5a'},
                    TargetPortID = {17, 49},
                    Slot = {3, 4},
                    Device = {}
                }
            }
        }, 
        {
            slot_type = 'IEU',
            slot_number = 3,
            silk_text = 'IEUSlot3',
            configs = {
                {
                    UID = '00000001040302064316',
                    Index = 0,
                    BCUIndex = 2,
                    SrcPortName = {'B1a', 'A4a'},
                    TargetPortID = {17, 49},
                    Slot = {1, 2},
                    Device = {}
                }
            }
        }
    },
    uid_list = {['00000001040302064316'] = true},
    uid_slot_list = {
        IEU = {[1] = '00000001040302064316', [2] = '00000001040302064316', [3] = '00000001040302064316'},
        SEU = {}
    }
}

-- BCU2的配置部分匹配，报线缆少插告警
function TestTopoMonitorNew:test_ieu_with_two_bcu4()
    -- 模拟bcu smc命令
    local biz_topo_node = create_biz_topo_node(test_ieu_with_two_configs_data_absent3.biz_topo_node,
        test_ieu_with_two_configs_data_absent3.BCU_SLOT)
    -- 模拟bcu的biz connector
    local conn_objs = create_biz_conn_objs(test_ieu_with_two_configs_data_absent3.biz_conn_data)
    -- 模拟psr的unit configuration
    local unit_confs = create_unit_conf_objs(test_ieu_with_two_configs_data_absent3.unit_conf_data)

    -- 创建线缆检测对象
    local topo_monitor = c_topo_monitor.new(bus, biz_topo_node, conn_objs, unit_confs)
    -- 输入当前自发现发现的uid列表
    topo_monitor.uid_list = test_ieu_with_two_configs_data_absent.uid_list
    topo_monitor.uid_slot_list = test_ieu_with_two_configs_data_absent.uid_slot_list

    -- 运行线缆检测逻辑
    run_topo_monitor(topo_monitor, conn_objs, unit_confs)

    -- 检查数据
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 5)
    lu.assertEquals(unit_confs[1].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot1)')
    
    lu.assertEquals(unit_confs[2].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 5)
    lu.assertEquals(unit_confs[2].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot2)')

    lu.assertEquals(unit_confs[3].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1Status, 5)
    lu.assertEquals(unit_confs[3].mds_obj['bmc.kepler.Systems.UnitConfigError'].Port1LinkInfo,
        '00000001040302064316(IEUSlot3)')        
end